# _*_conding:cp-1252-*-
# 教育机构：银杰教育
# 讲师：李伟
# 开发时间：2025/9/8 下午9:44
"""
封装的函数的优化：
1、记录日志： 方便问题定位 看到执行过程 == 但凡print看结果 或者debug看结果的地方都记录日志
优化：
定义参数 token 设置默认值None 因为有些时间不需要传token。

原始header= '{ "Content-Type": "multipart/form-data",
"Authorization":"bearerbbe67d27-972a-4474-86f2-9f8bc197a016"}'
现在需要在这个头部里 替换调用token值  通过参数传进来值。
"""
import json
import allure
import pytest
import requests
from tools.handle_path import photo
from tools.handle_path import file_path
from tools.handle_logs import logger
from tools.handle_extract import extract_response
from tools.handle_presql import pre_sql
from tools.handle_replace import replace_mark

@allure.step("发送接口请求")
def requests_api(case, token=None):  # 形参case   token默认参数None 因为有些时间不需要传token。
    method = case["请求方法"]
    url = case["接口地址"]
    header = case["请求头"]
    param = case["请求参数"]
    presql = case["前置SQL"]
    # 执行前置SQL之前，还要替换一下占位符 调用replace_mark方法
    presql = replace_mark(presql)
    # 在请求参数替换之前 执行前置sql
    pre_sql(presql)

    # 调用替换函数 替换头部 和参数 URL地址里的占位符
    header = replace_mark(header)  # 替换头部并把提花能完成后的字符串成赋值给变量header
    param = replace_mark(param)  # 替换参数并把提能完成后的字符串成赋值给变量param
    url = replace_mark(url)  # 替换url地址占位符并替换后的字符串成赋值给变量url

    # 发送接口请求之前，头部和参数需要做反序列操作 转化为字典
    # 因为有些接口没有请求头 /没有请求参数，所以在json.loads反序列化之前，要判空
    if header is not None:
        header = json.loads(header)  # 转化为字典了
        if token is not None:  # 如果存在token
            header["Authorization"] = token
    if param is not None:
        param = json.loads(param)  # 转化为字典了

    # 发送接口请求之前，接口请求方法有get post put等 各种方法都要支持,转化为小写之后再比对
    # 记录请求数据的日志
    logger.info("............请求消息...........")
    logger.info(f"请求方法是：{method}")
    logger.info(f"请求url是：{url}")
    logger.info(f"请求头部是：{header}")
    logger.info(f"请求参数是：{param}")
    resp = None # 避免警告 可以在最开始给他一个默认None
    if method.lower() == "get":
        resp = requests.request(method=method, url=url, headers=header, params=param)
    elif method.lower() == "post":  # 如果post方法，需要根据content-type类型判断用什么参数。
        if header["Content-Type"] == "application/json":
            resp = requests.request(method=method, url=url, headers=header, json=param)
        if header["Content-Type"] == "application/x-www-form-urlencoded":
            resp = requests.request(method=method, url=url, headers=header, data=param)
        if header["Content-Type"] == "multipart/form-data":
            # 如果是上传结果，一定不要加上content-type头部  删除头部
            header.pop("Content-Type")
            filename = param["filename"]
            # 做上传的文件路径处理: photo
            file_ojb = {"file": open(file_path / filename, "rb")}
            # file_path是路径处理data路径下  拼接filename实际传入的图片。
            resp = requests.request(method=method, url=url, files=file_ojb)
    elif method.lower() == "put":
        pass
    logger.info(".................响应消息................")
    logger.info(f"响应状态码：{resp.status_code}")
    logger.info(f"响应体：{resp.text}")
    # 得到响应消息之后 提取数据 调用提取函数
    extract_response(resp,case["提取响应字段"])
    return resp  # 由于有些数据未处理到方法，所以需要先给result一个初始化None 不会出现无法识别。


# "get":   #get方法需要params接收
# "post":
# "application/json":     #方法需要json接收
# "application/x-www-form-urlencoded": #方法需要data=接收
# "multipart/form-data":  如果是上传接口需要删除头部 files接收  request的bug
#

# 1. 明确变量作用域与初始值    resp =None
# 在 Python 中，变量需要先定义（赋值）才能使用。这里先将 resp 初始化为 None，是为了在后续的条件分支（if/elif）之外，也能保证 resp 是一个有定义的变量。
# 如果不先赋值 None，当所有条件分支都没有执行（比如 method 既不是 get、post，也不是 put 时），resp 就会因为没有被赋值而报错（UnboundLocalError，局部变量未定义）。
# 代码最后有 return resp，如果不提前给 resp 赋值，当没有任何条件分支命中时，return 的是一个未定义的变量，程序会报错。

# if __name__ == '__main__':
from tools.handle_excel import read_excel
from tools.handle_path import master_agent
from tools.handle_response_assert import response_assert

case_result = read_excel(master_agent, "login")


@pytest.mark.parametrize("case", case_result)  # 用于关联测试数据和函数参数；
def test_login(case):  # 形参接收
    test = requests_api(case)
    except_data = case["预期结果"]
    response_assert(test, except_data)


if __name__ == '__main__':
    pytest.main(["-s", __file__])  # 直接运行当前文件时，执行 pytest

# 装饰器中的 "case" 是参数名的定义（字符串形式），用于关联测试数据和函数参数；
# 函数中的 case 是实际接收数据的变量，用于在测试逻辑中引用参数化的数据。
# 两者名称必须一致，才能让 pytest 正确将 case_result 中的数据传递到测试函数中。


# 在这段代码里，pytest.main(["-s", __file__]) 的作用是调用 pytest 框架来运行当前脚本中的测试用例。"-s" 参数的作用是显示测试过程中的打印信息
# （如果有的话），__file__ 表示当前脚本的文件名，这样 pytest 就会找到并执行该脚本里的测试。
# 简单来说，这部分代码的目的是：当你直接运行这个脚本时，会自动使用 pytest 来执行其中的测试用例，方便测试的运行和调试

#封装总结：
# 1、读取每条用例函数case  case作为参数、token设置初始默认值None，因为有些接口请求用不到token
# 2、执行请求之前 需要执行前置SQL 执行替换。  然后在提取接口设置环境变量。
#     执行占位符替换后>执行前置SQL>请求>提取响应字段，设置环境变量，共下个接口使用环境变量中的值。
#       替换占位符：参数、头部都需要替换
#         header = replace_mark(reader)
#         param = replace_mark(param )